home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
exampleCode
/
smoke
/
smoke.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
9KB
|
369 lines
/*
* Copyright (c) 1993, 1994, Silicon Graphics, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that (i) the above copyright notices and this
* permission notice appear in all copies of the software and related
* documentation, and (ii) the name of Silicon Graphics may not be
* used in any advertising or publicity relating to the software
* without the specific, prior written permission of Silicon Graphics.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
* INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
* DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
* THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
* OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "uSmoke.h"
#include "uLinMath.h"
#include "smoke_ext.h" /* extern'd variables used in this module */
/*************************************************************/
/* [ 13A-1 ] */
void initPuff(uPuff *puff, uSmoke *smoke)
{
float *rv, r,s;
float offset[3];
float mat[4][4];
long i;
if(InitRand == 0)
{
for(i=0; i<MAX_RAND; i++)
{
RandVec3[i][0] = (float)(random() & 0xffff) / 32767.0f - 1.0f;
RandVec3[i][1] = (float)(random() & 0xffff) / 32767.0f - 1.0f;
RandVec3[i][2] = (float)(random() & 0xffff) / 32767.0f - 1.0f;
uNormalizeVec3(RandVec3[i]);
}
InitRand = 1;
}
puff->radius = smoke->radius;
uCopyVec3(puff->origin, smoke->origin);
puff->transp = 0.0f;
puff->startTime = smoke->lastPuffTime;
/* Add random velocity modifier */
if(smoke->type != USMOKE_MISSLE)
{
rv = RAND_VEC3;
uAddScaledVec3(puff->direction, smoke->direction, .15f, rv);
}
else
uCopyVec3(puff->direction, smoke->direction);
s = smoke->expansion * smoke->radius * .05f;
uScaleVec3(offset, s, puff->direction); /*puff->direction was rv, ?bug?*/
uAddVec3(puff->origin, puff->origin, offset);
r = ((random() & 0xff) / 255.0f - .5f) * 4.0f * smoke->turbulence;
uMakeTransMat(puff->rotMat, -0.5f, -0.5f, 0.0f);
uMakeRotMat(mat, r, 0.0f, 0.0f, 1.0f);
uPostMultMat(puff->rotMat, mat);
uMakeTransMat(mat, 0.5f, 0.5f, 0.0f);
uPostMultMat(puff->rotMat, mat);
r = 1.0f + ((random() & 0xffff) / 65535.0f + -.5f) * .1f;
puff->speed = r * smoke->speed;
}
/* [ 13A ] */
void drawSmoke(uSmoke *smoke, uVec3 eye)
{
double now = uGetTime();
double deltaTime, age = 1.0f;
float speed, *tmp;
float puffInterval, puffDiss;
uVec3 dist;
long i, n, startPuff;
/* Compute time elapsed from previous uDrawSmoke */
if(smoke->prevTime < 0.0f)
deltaTime = 0.0f;
else
deltaTime = now - smoke->prevTime;
smoke->prevTime = now;
if(smoke->startTime < 0.0f)
smoke->startTime = now;
if(smoke->duration > 0.0f)
{
age = 1.0 - (now - smoke->startTime) / smoke->duration;
if(age <= 0.0)
{
smoke->mode = USMOKE_STOP;
smoke->startTime = -1.;
smoke->lastPuffTime = -1.;
return;
}
age += .01f;
}
if (smoke->type != USMOKE_EXPLOSION)
{
puffInterval = smoke->puffInterval / age;
puffDiss = smoke->dissipation/smoke->density * age; /*needed density*/
}
else
{
puffInterval = smoke->puffInterval;
puffDiss = smoke->dissipation/smoke->density;
}
/* Initialize new puff of smoke if necessary */
if(now - smoke->lastPuffTime >= puffInterval)
{
uPuff *puff;
smoke->lastPuffTime = now;
puff = smoke->puffs[(smoke->startPuff + smoke->numPuffs) % MAX_PUFFS];
initPuff(puff, smoke); /* 13A-1*/
smoke->numPuffs++;
}
if(smoke->tex) {
uApplyTex(smoke->tex);
}
n = smoke->numPuffs;
startPuff = smoke->startPuff;
for(i=n-1; i>=0; i--)
{
uPuff *puff = smoke->puffs[(i+startPuff) % MAX_PUFFS];
/*
* Dissipate puff based on dissipation rate
*/
puff->t = (now - puff->startTime) / puffDiss;
/* Get rid of puff if completely transparent */
if(puff->t >= 1.0f)
{
smoke->startPuff = (smoke->startPuff + 1) % MAX_PUFFS;
smoke->numPuffs--;
continue;
}
/*
* Transparency is cubed so it quickly dissipates as dissipation
* time is neared.
*/
puff->transp = puff->t * puff->t * puff->t * puff->t;
if(smoke->type == USMOKE_EXPLOSION)
{
/* Radius is linear interpolation between 0 and expansion */
puff->radius = (now - puff->startTime) / puffDiss *
smoke->expansion * smoke->radius;
}
else
{
/* Radius is linear interpolation between radius and expansion */
puff->radius = (1.0f - puff->transp) * smoke->radius +
puff->transp * smoke->expansion * smoke->radius;
}
speed = puff->speed * deltaTime;
uScaleVec3(dist, speed, puff->direction);
/* Translate puff based on velocity vector */
{
tmp = puff->origin;
uAddVec3(tmp, tmp, dist);
}
/* Fade in brand new puff */
if(i == smoke->numPuffs - 1
&& smoke->type != USMOKE_EXPLOSION && smoke->type != USMOKE_FIRE)
{
puff->transp = 1.0f - (now - puff->startTime) / puffInterval;
}
drawPuff(puff, smoke, eye);
}
}
#define SQRT3_2 .86602540378443864676f
void cross(uVec3 AN, uVec3 BN, uVec3 CN, float *nx, float *ny, float *nz);
/* [ 13B ] */
void drawPuff(uPuff *puff, uSmoke *smoke, uVec3 eye)
{
uVec4 opaque;
long i;
float r = puff->radius, *org = puff->origin;
uVec3 norm,norm_d;
static int pc=0;
float *t2;
#define Zv 0.0
static float t2a[]={0,0,1,0,1,1,0,1};
static float t2b[]={1,0,Zv,1,1,Zv,0,1,Zv,0,0,Zv};
static float t2c[]={1,1,0,1,0,0,1,0};
static float t2d[]={0,1,0,0,1,0,1,1};
static uVec3 quad[] = {
{-1.0f, 0.0f, -1.0f},
{1.0f, 0.0f, -1.0f},
{1.0f, 0.0f, 1.0f},
{-1.0f, 0.0f, 1.0f}
};
uVec3 dquad[6], toEye;
uMatrix mat;
static uVec3 vec = {0.0f, -1.0f, 0.0f};
/* Fade fire to black smoke */
if (smoke->type == USMOKE_FIRE)
{
uAddScaledVec3(opaque, smoke->bgnColor, puff->transp, smoke->deltaColor);
opaque[3] = 1.0f;
}
else
{
uAddScaledVec3(opaque, smoke->bgnColor, puff->t, smoke->deltaColor);
opaque[3] = 1.0f - puff->transp;
}
/*
* Compute matrix which rotates puff to face the eyepoint
*/
uSubVec3(toEye, eye, puff->origin);
uMakeRotOntoMat(mat, vec, toEye);
for(i=0; i<4; i++)
{
uVec3 svert;
/* Scale quad to current radius */
uScaleVec3(svert, puff->radius, quad[i]);
/* Offset puff based on radius */
svert[1] -= smoke->radius;
/* Rotate puff to follow viewer */
uXformPt3(dquad[i], svert, mat);
/* Translate puff to origin */
uAddVec3(dquad[i], dquad[i], puff->origin);
}
#if 0
switch(pc++) {
case 0:
t2 = t2b;
break;
case 1:
t2 = t2c;
break;
case 2:
t2 = t2d;
break;
case 3:
t2 = t2a;
pc = 0;
break;
}
#else
t2 = t2b;
#endif
#if NOTEXTURE
#define T2F(t)
#else
#define T2F(t) t2f((t))
#endif
lmcolor(LMC_DIFFUSE);
c4f(opaque);
bgnpolygon();
cross(dquad[0],dquad[1],dquad[2],&norm[0],&norm[1],&norm[2]);
norm_d[0]=(dquad[0][0]-norm[0]);
norm_d[1]=(dquad[0][1]-norm[1]);
norm_d[2]=(dquad[0][2]-norm[2]);
n3f(norm);
T2F(t2);
v3f(dquad[0]);
T2F(t2+3);
v3f(dquad[1]);
T2F(t2+6);
v3f(dquad[2]);
T2F(t2+9);
v3f(dquad[3]);
endpolygon();
#if NOTEXTURE
bgnline();
v3f(dquad[0]);
v3f(norm_d);
endline();
#endif
}
#define X1 AN[0]
#define Y1 AN[1]
#define Z1 AN[2]
#define X2 BN[0]
#define Y2 BN[1]
#define Z2 BN[2]
#define X3 CN[0]
#define Y3 CN[1]
#define Z3 CN[2]
void cross(uVec3 AN, uVec3 BN, uVec3 CN, float *nx, float *ny, float *nz)
{
float vx1,vy1,vz1, vx2,vy2,vz2, x,y,z, dis;
/* find the two vectors */
vx1 = X1-X2;
vy1 = Y1-Y2;
vz1 = Z1-Z2;
vx2 = X3-X2;
vy2 = Y3-Y2;
vz2 = Z3-Z2;
/* get their cross product */
x = vy1*vz2 - vz1*vy2;
y = vz1*vx2 - vx1*vz2;
z = vx1*vy2 - vy1*vx2;
dis = sqrtf(x*x + y*y + z*z);
if(dis == 0.0) dis=0.000001;
*nx = -x/dis;
*ny = -y/dis;
*nz = -z/dis;
} /* cross_product */